package com.appspot.moviesessions;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;


public class EventPublisherImpl implements EventPublisher {
	
	private Map<Class,List<EventListener>> registery = new HashMap<Class, List<EventListener>>() ;
	@Override
	public <T extends ApplicationEvent> void register(EventListener<T> listener) {
		getListeners(resolveEventType(listener)).add(listener);
		
	}

	private <T> List<EventListener> getListeners(Class<T> t) {
		if(!registery.containsKey(t)){
			registery.put(t, new ArrayList<EventListener>());
		}
	    return registery.get(t);
    }
	
	private <T extends ApplicationEvent> Class<T> resolveEventType(EventListener<T> listener){
		Type genericSuperclass = listener.getClass().getGenericInterfaces()[0];
		if(ParameterizedType.class.isInstance(genericSuperclass)){
			Object type = ((Class) ((ParameterizedType) genericSuperclass).getActualTypeArguments()[0]);
			return (Class<T>) type;	
		}
		
		return (Class<T>) ApplicationEvent.class;
		
	}
	
	
	@Override
	public <T extends ApplicationEvent> void publish(T event) {
		Set<Class> keys = registery.keySet();
		List<EventListener> listeners = new ArrayList<EventListener>();
		for (Class key : keys) {
	        if(key.isAssignableFrom(event.getClass())){
	        	listeners.addAll(registery.get(key));
	        }
        }
		for (EventListener listener : listeners) {

			listener.onEvent(event);
	        
        }

	}
	
	
}
